<?php

namespace maotool\util;

use maotool\exception\RuntimeException;

/**
 * 数学工具类
 */
class MathUtil
{

    /**
     * 十分比计算
     * @param $total
     * @param $part
     * @param $precision
     * @param $model
     * @param bool $max 是否限制最大值为$cut
     * @return float|string
     */
    public static function tenPercent($total, $part, $precision = 0, $model = true, $max = false)
    {
        return PercentageUtil::tenPercent($total, $part, $precision, $model, $max);
    }

    /**
     * 百分比计算
     * @param $total
     * @param $part
     * @param $precision
     * @param $model
     * @param bool $max 是否限制最大值为$cut
     * @return float|string
     */
    public static function percentage($total, $part, $precision = 0, $model = true, $max = false)
    {
        return PercentageUtil::percentage($total, $part, $precision, $model, $max);
    }

    /**
     * 千分比计算
     * @param $total
     * @param $part
     * @param $precision
     * @param $model
     * @param bool $max 是否限制最大值为$cut
     * @return float|string
     */
    public static function thousandthRatio($total, $part, $precision = 0, $model = true, $max = false)
    {
        return PercentageUtil::thousandthRatio($total, $part, $precision, $model, $max);
    }

    /**
     * 自定义分比计算
     * @param $total
     * @param $part
     * @param $cut
     * @param $precision
     * @param $model
     * @param bool $max 是否限制最大值为$cut
     * @return float|string
     */
    public static function cutCalculate($total, $part, $cut = 100, $precision = 0, $model = true, $max = false)
    {
        return PercentageUtil::cutCalculate($total, $part, $cut, $precision, $model, $max);
    }

    /**
     * 加法运算
     *
     * @param float $a 被加数
     * @param float $b 加数
     * @return float 运算结果
     */
    public static function add($a, $b)
    {
        return $a + $b;
    }

    /**
     * 减法运算
     *
     * @param float $a 被减数
     * @param float $b 减数
     * @return float 运算结果
     */
    public static function subtract($a, $b)
    {
        return $a - $b;
    }

    /**
     * 乘法运算
     *
     * @param float $a 被乘数
     * @param float $b 乘数
     * @return float 运算结果
     */
    public static function multiply($a, $b)
    {
        return $a * $b;
    }

    /**
     * 除法运算
     *
     * @param float $a 被除数
     * @param float $b 除数
     * @return float 运算结果
     * @throws RuntimeException 当除数为0时抛出异常
     */
    public static function divide($a, $b)
    {
        if ($b == 0) {
            throw new RuntimeException("除数不能为零");
        }
        return $a / $b;
    }

    /**
     * 取模运算
     *
     * @param float $a 被除数
     * @param float $b 除数
     * @return float 运算结果
     * @throws RuntimeException 当除数为0时抛出异常
     */
    public static function modulo($a, $b)
    {
        if ($b == 0) {
            throw new RuntimeException("除数不能为零");
        }
        return $a % $b;
    }

    /**
     * 幂运算
     *
     * @param float $base 底数
     * @param float $exponent 指数
     * @return float 运算结果
     */
    public static function power($base, $exponent)
    {
        return pow($base, $exponent);
    }

    /**
     * 开方运算
     *
     * @param float $number 被开方数
     * @return float 运算结果
     * @throws RuntimeException 当被开方数为负数时抛出异常
     */
    public static function sqrt($number)
    {
        if ($number < 0) {
            throw new RuntimeException("负数不能开平方根");
        }
        return sqrt($number);
    }

    /**
     * 人民币单位转换：分转元
     *
     * @param float $cent 分
     * @param int $precision 保留小数位数
     * @return float 转换后的元
     */
    public static function centToYuan($cent, $precision = 2)
    {
        return round($cent / 100, $precision);
    }

    /**
     * 人民币单位转换：元转分
     *
     * @param float $yuan 元
     * @return int 转换后的分
     */
    public static function yuanToCent($yuan)
    {
        return (int)round($yuan * 100);
    }

    /**
     * 数量级单位转换：转为百
     *
     * @param float $number 原数值
     * @param int $precision 保留小数位数
     * @return float 转换后的数值
     */
    public static function toHundred($number, $precision = 2)
    {
        return round($number / 100, $precision);
    }

    /**
     * 数量级单位转换：转为千
     *
     * @param float $number 原数值
     * @param int $precision 保留小数位数
     * @return float 转换后的数值
     */
    public static function toThousand($number, $precision = 2)
    {
        return round($number / 1000, $precision);
    }

    /**
     * 数量级单位转换：转为万
     *
     * @param float $number 原数值
     * @param int $precision 保留小数位数
     * @return float 转换后的数值
     */
    public static function toTenThousand($number, $precision = 2)
    {
        return round($number / 10000, $precision);
    }

    /**
     * 数量级单位转换：转为千万
     *
     * @param float $number 原数值
     * @param int $precision 保留小数位数
     * @return float 转换后的数值
     */
    public static function toTenMillion($number, $precision = 2)
    {
        return round($number / 10000000, $precision);
    }

    /**
     * 数量级单位转换：转为亿
     *
     * @param float $number 原数值
     * @param int $precision 保留小数位数
     * @return float 转换后的数值
     */
    public static function toHundredMillion($number, $precision = 2)
    {
        return round($number / 100000000, $precision);
    }

    /**
     * 自定义单位转换
     *
     * @param float $number 原数值
     * @param float $unit 单位倍数（例如：100表示"百"，10000表示"万"）
     * @param int $precision 保留小数位数
     * @return float 转换后的数值
     */
    public static function convertUnit($number, $unit, $precision = 2)
    {
        if ($unit == 0) {
            throw new RuntimeException("单位倍数不能为零");
        }
        return round($number / $unit, $precision);
    }

    /**
     * 数量级单位转换：转为百万
     *
     * @param float $number 原数值
     * @param int $precision 保留小数位数
     * @return float 转换后的数值
     */
    public static function toMillion($number, $precision = 2)
    {
        return round($number / 1000000, $precision);
    }

    /**
     * 数量级单位转换：转为十万
     *
     * @param float $number 原数值
     * @param int $precision 保留小数位数
     * @return float 转换后的数值
     */
    public static function toHundredThousand($number, $precision = 2)
    {
        return round($number / 100000, $precision);
    }

    /**
     * 将金额转换为自动适配单位的字符串表示
     *
     * @param float $amount 金额（元）
     * @param array $units 自定义单位配置数组，按从大到小顺序排列
     *   格式：[['value' => 100000000, 'unit' => '亿元'], ...]
     * @param int $precision 保留小数位数
     * @return string 带自动适配单位的金额字符串
     */
    public static function formatAmountAutoUnit($amount, $units = [
        ['value' => 100000000, 'unit' => '亿元'],
        ['value' => 10000000, 'unit' => '千万元'],
        ['value' => 1000000, 'unit' => '百万元'],
        ['value' => 100000, 'unit' => '十万元'],
        ['value' => 10000, 'unit' => '万元'],
        ['value' => 1000, 'unit' => '千元'],
        ['value' => 100, 'unit' => '百元'],
        ['value' => 10, 'unit' => '十元'],
        ['value' => 1, 'unit' => '元']
    ], $precision = 2)
    {
        $absAmount = abs($amount);

        // 遍历单位配置数组，找到最适合的单位
        foreach ($units as $unitConfig) {
            if (isset($unitConfig['value']) && isset($unitConfig['unit']) &&
                $unitConfig['value'] > 0 && $absAmount >= $unitConfig['value']) {
                return round($amount / $unitConfig['value'], $precision) . $unitConfig['unit'];
            }
        }

        // 如果没有匹配的单位（理论上不会发生，因为最小单位是1元），则返回原始金额
        return round($amount, $precision) . '元';
    }


}